﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
namespace AlumnoEjemplos.TP3D.Collider
{
    public class CollisionEngine
    {
        protected List<CollisionSurface> _massives = new List<CollisionSurface>();
        protected List<CollisionSurface> _collisionables = new List<CollisionSurface>();
        protected Dictionary<CollisionSurface, List<Placeable>> _analisisMap = new Dictionary<CollisionSurface,List<Placeable>>();
        protected float ElapsedTime;
        protected List<Placeable> emptyList = new List<Placeable>();
        protected bool _makeRender;
        public static float TIME = 0.0001f;
        protected static CollisionEngine instance = null;


        public static CollisionEngine Instance() {
            if (CollisionEngine.instance == null)
            {
                CollisionEngine.instance = new CollisionEngine();
            }
            return CollisionEngine.instance;
        }


        public bool MakeRender
        {
            set { this._makeRender = value;  }
            get { return this._makeRender;}
        }
        public void Render(float elapsedTime) {
            if (elapsedTime < CollisionEngine.TIME || !this.MakeRender) return;
            foreach (CollisionSurface c in this.Massives) c.Render();
        }
        protected CollisionEngine () {
        }
        #region Accessors

        public Dictionary<CollisionSurface, List<Placeable>> CollisionMap {
            get { return this._analisisMap;  }
        }
        public List<CollisionSurface> Massives 
        {
            set { this._massives = value;  }
            get { return this._massives;  }
        }

        public List<CollisionSurface> Collisionables
        {
            set { this._collisionables = value; }
            get { return this._collisionables; }
        }
        #endregion

        public CollisionEngine UseEnlapsedTime(float EnlapsedTime) {
            this.ElapsedTime = EnlapsedTime;
            return this;
        }

        public void AddMassivePlaceableInAMobileBox(Placeable p, Vector3 minVertex, Vector3 maxVertex) {
            CollisionMobileBox box = new CollisionMobileBox(p);
            box.MaxVertex = maxVertex;
            box.MinVertex = minVertex;
            this.AddMassive(box);
        }
        public void AddMassivePlaceableInASphere(Placeable p, float radio)
        {
            CollisionSphere sphere = new CollisionSphere(p);
            sphere.Radio = radio;
            this.AddMassive(sphere);
        }

        public void AddCollisionablePlaceableInAMobileBox(Placeable p, Vector3 minVertex, Vector3 maxVertex)
        {
            CollisionMobileBox box = new CollisionMobileBox(p);
            box.MaxVertex = maxVertex;
            box.MinVertex = minVertex;
            this.AddCollisionable(box);
        }
        public void AddCollisionablePlaceableInASphere(Placeable p, float radio)
        {
            CollisionSphere sphere = new CollisionSphere(p);
            sphere.Radio = radio;
            this.AddCollisionable(sphere);
        }
        public void AddMassive(CollisionSurface aSurface) {
            this.Massives.Add(aSurface);
            this.CollisionMap.Add(aSurface, this.emptyList);
        }

        public void AddCollisionable(CollisionSurface aSurface) {
            this.Collisionables.Add(aSurface);
        }
        public List<Placeable> AnalizePlaceableCollisions(Placeable placeable) {
            foreach (CollisionSurface s in this.Massives) {
                if (s.Surrounded == placeable) {
                    return this.AnalizeSurfaceCollisions(s);
                }
            }
            foreach (CollisionSurface s in this.Collisionables)
            {
                if (s.Surrounded == placeable)
                {
                    return this.AnalizeSurfaceCollisions(s);
                }
            }
            throw new Exception("Se trato de analizar un placeable que no esta registrado!");
        }
        public List<Placeable> AnalizeSurfaceCollisions(CollisionSurface aSurface)
        { 
            List<Placeable> collided = new List<Placeable>();
            if (this.ElapsedTime < CollisionEngine.TIME)
            {
                return this.CollisionMap[aSurface];
            }
            foreach (CollisionSurface collisionable in this.Collisionables){
                if (collisionable.Collides(aSurface)) {
                    collided.Add(collisionable.Surrounded);
                }
            }
            foreach (CollisionSurface collisionable in this.Massives) {
                if (collisionable.Collides(aSurface)) {
                    collided.Add(collisionable.Surrounded);
                }
            }
            return collided;
        }
        public void Analize() {
            if (this.ElapsedTime < CollisionEngine.TIME) return;
            foreach (CollisionSurface surface in this.Massives) {
                this._analisisMap.Add(surface, this.AnalizeSurfaceCollisions(surface));
            }
        }
        public void ManageCollisions(Placeable placeable)
        {
            List<Placeable> p = this.AnalizePlaceableCollisions(placeable);
            if (p.Count > 0)
            {
                foreach (Placeable pl in p)
                {
                    pl.doSomethingToMassive(placeable);
                }
            }
        }

        internal void RemovePlaceable(Placeable placeable)
        {
            IList<CollisionSurface> sarasasToRemove = new List<CollisionSurface>();
            foreach (CollisionSurface s in this.Massives)
            {
                if (s.Surrounded == placeable)
                {
                    sarasasToRemove.Add(s);
                }
            }

            foreach (CollisionSurface collisionSurface in sarasasToRemove)
            {
                this.Massives.Remove(collisionSurface);
            }

            IList<CollisionSurface> masSarasasToRemove = new List<CollisionSurface>();
            foreach (CollisionSurface s in this.Collisionables)
            {
                if (s.Surrounded == placeable)
                {
                    masSarasasToRemove.Add(s);
                }
            }

            foreach (CollisionSurface collisionSurface in masSarasasToRemove)
            {
                this.Collisionables.Remove(collisionSurface);
            }
        }
    }
}
